package gormgen

import (
	"gorm.io/gen"
	"gorm.io/gen/field"
	"gorm.io/gorm"
	"strings"
)

var DefaultConfig = gen.Config{
	//相对执行 go run 时的路径，会自动创建目录
	OutPath:      "./dal",
	OutFile:      "",
	ModelPkgPath: "",
	WithUnitTest: true,
	//表字段可为null值时，对应结构体字段使用指针类型
	FieldNullable: false,
	// 表字段默认值与模型结构体字段零值不一致的字段, 在插入数据时需要赋值该字段值为零值的, 结构体字段须是指针类型才能成功, 即`FieldCoverable:true`配置下生成的结构体字段.
	// 因为在插入时遇到字段为零值的会被GORM赋予默认值. 如字段`age`表默认值为10, 即使你显式设置为0最后也会被GORM设为10提交.
	// 如果该字段没有上面提到的插入时赋零值的特殊需要, 则字段为非指针类型使用起来会比较方便.
	FieldCoverable: false,
	// 模型结构体字段的数字类型的符号表示是否与表字段的一致, `false`指示都用有符号类型
	FieldSignable: false,
	// 生成 gorm 标签的字段索引属性
	FieldWithIndexTag: true,
	// 生成 gorm 标签的字段类型属性
	FieldWithTypeTag: true,
	// WithDefaultQuery 生成默认查询结构体(作为全局变量使用), 即`Q`结构体和其字段(各表模型)
	// WithoutContext 生成没有context调用限制的代码供查询
	// WithQueryInterface 生成interface形式的查询代码(可导出), 如`Where()`方法返回的就是一个可导出的接口类型
	Mode: gen.WithDefaultQuery | gen.WithQueryInterface | gen.WithoutContext,
}

// DefaultDataTypeMap 自定义字段的数据类型
// 统一数字类型为int64,兼容protobuf
// 要先于`ApplyBasic`执行
var DefaultDataTypeMap = map[string]func(columnType gorm.ColumnType) (dataType string){
	"tinyint": func(columnType gorm.ColumnType) (dataType string) {
		if t, ok := columnType.ColumnType(); ok {
			if strings.Contains(t, "tinyint(1)") {
				return "bool"
			}
		}
		return "int64"
	},
	"smallint":  func(columnType gorm.ColumnType) (dataType string) { return "int64" },
	"mediumint": func(columnType gorm.ColumnType) (dataType string) { return "int64" },
	"int":       func(columnType gorm.ColumnType) (dataType string) { return "int64" },
	"bigint":    func(columnType gorm.ColumnType) (dataType string) { return "int64" },
}

// DefaultModelOption 模型自定义选项组
// 将非默认字段名的字段定义为自动时间戳和软删除字段;
// 自动时间戳默认字段名为:`updated_at`、`created_at, 表字段数据类型为: INT 或 DATETIME
// 软删除默认字段名为:`deleted_at`, 表字段数据类型为: DATETIME
var DefaultModelOption = []gen.ModelOpt{
	gen.FieldGORMTag("updated_at", func(tag field.GormTag) field.GormTag {
		tag.Set("autoUpdateTime", "milli")
		return tag
	}), gen.FieldGORMTag("created_at", func(tag field.GormTag) field.GormTag {
		tag.Set("autoCreateTime", "milli")
		return tag
	}), gen.FieldType("deleted_at", "soft_delete.DeletedAt"),
}

func GenerateWithDefaultConfig(db *gorm.DB, tableNames []string, params ...[]interface{}) {
	g := gen.NewGenerator(DefaultConfig)
	g.UseDB(db)
	g.WithDataTypeMap(DefaultDataTypeMap)
	var models []interface{}
	for _, v := range tableNames {
		models = append(models, g.GenerateModel(v, DefaultModelOption...))
	}
	//创建模型的方法，生成文件在query目录，先创建结果不会被后创建的覆盖
	g.ApplyBasic(models...)

	//自定义创建查询
	for _, val := range params {
		param := val
		if len(param) == 2 {
			model := g.GenerateModel(param[1].(string), DefaultModelOption...)
			g.ApplyInterface(param[0], model)
		}
	}

	g.Execute()
}
